/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

/* global cordova */

var argscheck = require('cordova/argscheck');
var exec = require('cordova/exec');
var utils = require('cordova/utils');
var CompassHeading = require('./CompassHeading');
var CompassError = require('./CompassError');

var timers = {};
var eventTimerId = null;
var compass = {
    /**
     * Asynchronously acquires the current heading.
     * @param {Function} successCallback The function to call when the heading
     * data is available
     * @param {Function} errorCallback The function to call when there is an error
     * getting the heading data.
     * @param {CompassOptions} options The options for getting the heading data (not used).
     */
    getCurrentHeading: function (successCallback, errorCallback, options) {
        argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments);

        var win = function (result) {
            var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp);
            successCallback(ch);
        };
        var fail =
            errorCallback &&
            function (code) {
                var ce = new CompassError(code);
                errorCallback(ce);
            };

        // Get heading
        exec(win, fail, 'Compass', 'getHeading', [options]);
    },

    /**
     * Asynchronously acquires the heading repeatedly at a given interval.
     * @param {Function} successCallback The function to call each time the heading
     * data is available
     * @param {Function} errorCallback The function to call when there is an error
     * getting the heading data.
     * @param {HeadingOptions} options The options for getting the heading data
     * such as timeout and the frequency of the watch. For iOS, filter parameter
     * specifies to watch via a distance filter rather than time.
     */
    watchHeading: function (successCallback, errorCallback, options) {
        argscheck.checkArgs('fFO', 'compass.watchHeading', arguments);
        // Default interval (100 msec)
        var frequency = options !== undefined && options.frequency !== undefined ? options.frequency : 100;
        var filter = options !== undefined && options.filter !== undefined ? options.filter : 0;

        var id = utils.createUUID();
        if (filter > 0) {
            // is an iOS request for watch by filter, no timer needed
            timers[id] = 'iOS';
            compass.getCurrentHeading(successCallback, errorCallback, options);
        } else {
            // Start watch timer to get headings
            timers[id] = window.setInterval(function () {
                compass.getCurrentHeading(successCallback, errorCallback);
            }, frequency);
        }

        if (cordova.platformId === 'browser' && !eventTimerId) {
            // Start firing deviceorientation events if haven't already
            var deviceorientationEvent = new Event('deviceorientation');
            eventTimerId = window.setInterval(function () {
                window.dispatchEvent(deviceorientationEvent);
            }, 200);
        }

        return id;
    },

    /**
     * Clears the specified heading watch.
     * @param {String} id The ID of the watch returned from #watchHeading.
     */
    clearWatch: function (id) {
        // Stop javascript timer & remove from timer list
        if (id && timers[id]) {
            if (timers[id] !== 'iOS') {
                clearInterval(timers[id]);
            } else {
                // is iOS watch by filter so call into device to stop
                exec(null, null, 'Compass', 'stopHeading', []);
            }
            delete timers[id];

            if (eventTimerId && Object.keys(timers).length === 0) {
                // No more watchers, so stop firing 'deviceorientation' events
                window.clearInterval(eventTimerId);
                eventTimerId = null;
            }
        }
    }
};

module.exports = compass;


